use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use super::{Class, ClassAttributeBuilder, ClassBuilder, ClassGetter};
use crate::error::Error;
use crate::mapper::ValueMapper;
use crate::modeling::{
    ClassAttributePersistence, ClassPersistence, ClassPersistenceBuilder, ClassPersistenceGetter,
    ClassRelationGetter, Value, ValueType,
};

pub const CLASS_RELATION_CLASS_IDENTIFIER: &'static str = "g01_class_relation";

pub const CLASS_RELATION_CLASS_NAME: &'static str = "class_relation";

pub const CLASS_RELATION_TABLE_NAME: &'static str = "_g01_meta_class_relations";

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub enum RelationDirection {
    #[serde(rename = "reverse")]
    Reverse,
    #[default]
    #[serde(rename = "obverse")]
    Obverse,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub enum RelationRelatedType {
    #[serde(rename = "keys")]
    Keys,
    #[default]
    #[serde(rename = "class")]
    Class,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "ClassRelationBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct ClassRelation {
    /// id
    pub id: i64,
    /// relation identity
    pub relation_identifier: String,
    /// 源
    pub src_identifier: String,
    /// 目标
    pub target_identifier: String,
    /// src_count
    pub src_count: i64,
    /// target_count
    pub target_count: i64,
    /// related_type
    pub related_type: RelationRelatedType,
    /// related_at
    pub related_at: String,
    /// 选项
    pub options: Option<String>,
    /// 备注
    pub description: String,
    // 创建时间
    pub created_at: i64,
    // 更新时间
    pub updated_at: i64,
}

impl ValueMapper for ClassRelation {}
//
crate::impl_from_value!(ClassRelation);
crate::impl_class_persistence_getter!(ClassRelation, CLASS_RELATION_TABLE_NAME);
crate::impl_class_relations_getter!(
    ClassRelation,
    vec![
        ClassRelationBuilder::default()
            .src_identifier(Class::get_identifier()?)
            .target_identifier(Self::get_identifier()?)
            .related_type(RelationRelatedType::Keys)
            .related_at("src_identifier")
            .build()?,
        ClassRelationBuilder::default()
            .src_identifier(Class::get_identifier()?)
            .target_identifier(Self::get_identifier()?)
            .related_type(RelationRelatedType::Keys)
            .related_at("target_identifier")
            .build()?
    ]
);

impl ClassGetter for ClassRelation {
    fn get_name() -> anyhow::Result<String> {
        Ok(String::from(CLASS_RELATION_CLASS_NAME))
    }

    fn get_identifier() -> anyhow::Result<String> {
        Ok(String::from(CLASS_RELATION_CLASS_IDENTIFIER))
    }
    fn get_class() -> anyhow::Result<Class> {
        let mut attribute_builder = ClassAttributeBuilder::default();
        attribute_builder.class_identifier(CLASS_RELATION_CLASS_IDENTIFIER);

        let mut commons = super::common_attributes_with_builder(&attribute_builder)?;
        let mut append = vec![
            attribute_builder
                .clone()
                .name("relation_identifier")
                .title("领域")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("src_identifier")
                .title("源类型")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("target_identifier")
                .title("目标类型")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("src_count")
                .title("源数量")
                .data_type(ValueType::Number)
                .build()?,
            attribute_builder
                .clone()
                .name("target_count")
                .title("目标数量")
                .data_type(ValueType::Number)
                .build()?,
            attribute_builder
                .clone()
                .name("related_type")
                .title("相关类型")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("related_at")
                .data_type(ValueType::String)
                .title("相关在")
                .build()?,
        ];
        append.append(&mut commons);
        append.sort_by(|a, b| a.position.cmp(&b.position));
        let clazz = ClassBuilder::default()
            .identifier(CLASS_RELATION_CLASS_IDENTIFIER)
            .name(CLASS_RELATION_CLASS_NAME)
            .data_is_type(true)
            .is_persistent(true)
            .primary_key(String::from("identifier"))
            .attributes(append)
            .build()?;
        Ok(clazz)
    }
}
